﻿using AutoMapper;
using JunionRobotTaskManager.Dtos;
using JunionRobotTaskManager.Models;
using JunionRobotTaskManager.Repository;
using JunionRobotTaskManager.Utility;
using LazyCache;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using MySqlX.XDevAPI.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SqlSugar;
using System.ComponentModel;
using System.Reflection;

namespace JunionRobotTaskManager.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class JobController : ControllerBase
    {
        #region  Filed

        /// <summary>
        /// 日志记录
        /// </summary>
        private readonly ILogger<JobController> _logger;

        /// <summary>
        /// 任务信息
        /// </summary>
        private readonly IJobRepoitory _jobRepoitory;

        /// <summary>
        ///料口信息
        /// </summary>
        private readonly ITransferPortRepository _transferPortRepository;

        /// <summary>
        /// 机器人信息
        /// </summary>
        private readonly IRobotRepository _robotRepository;

        /// <summary>
        /// 系统配置新
        /// </summary>
        private readonly IOptionsMonitor<SystemInfo> _options;

        /// <summary>
        /// 缓存信息
        /// </summary>
        private readonly IMemoryCache _mCache;

        #endregion

        public JobController(ILogger<JobController> logger,
             ITransferPortRepository deliveryRepository,
              IOptionsMonitor<SystemInfo> options,
             IRobotRepository robotJobRepoitory,
             IJobRepoitory jobRepoitory,
            IMemoryCache mCache)
        {
            _logger = logger;
            _jobRepoitory = jobRepoitory;
            _mCache = mCache;
            _transferPortRepository = deliveryRepository;
            _robotRepository = robotJobRepoitory;
            _options = options;
        }


        #region 创建

        /// <summary>
        /// 创建任务
        /// </summary>
        /// <param name="job">新的任务</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult<ApiResult>> Create([FromBody] Job job)
        {
            try
            {
                #region 信息校验
                if (_jobRepoitory.CheckExist(x => x.Id == job.Id))
                {
                    if(_jobRepoitory.CheckExist(x=>x.Id==job.Id&&x.Status==TaskState.Pending))
                    {
                        var result = _jobRepoitory.UpdateEntity(job);
                        if(result)
                            return ApiResultHelper.Success($"任务{job.Id}已存在,更新成功");
                        else
                            return ApiResultHelper.Error($"任务{job.Id}已存在,但更新失败");
                    }
                    else
                    {
                        var errorInfo = $"任务创建失败,Mission重复{job.Id}";
                        _logger.LogError(errorInfo);
                        return ApiResultHelper.Error(errorInfo);
                    }
                   
                }

                var ids = _transferPortRepository.Query().Select(x=>x.Id);
                if (job.Targets == null && !job.Targets.Keys.ToList().All(t=>ids.Any(j=>j==t)))
                {
                    var errorInfo = $"Targets不能为空且Targets必须和RMS中的TransPorts的Id相同";
                    _logger.LogError(errorInfo);
                    return ApiResultHelper.Error(errorInfo);
                }

                #endregion

                #region 添加
                job.CreateTime = DateTime.Now;
                bool b = await _jobRepoitory.AddAsync(job);
                if (!b)
                {
                    var errorInfo = $"添加失败，服务器发生错误";
                    _logger.LogError(errorInfo);
                    return ApiResultHelper.Error(errorInfo);
                }
                #endregion

                return ApiResultHelper.Success("succeed");
            }
            catch (Exception ex)
            {
                var errorInfo = $"添加出错!服务器发生错误:{ex.Message}";
                _logger.LogError(errorInfo);
                return ApiResultHelper.Error(errorInfo);
            }


        }
        #endregion

        #region 取消
        /// <summary>
        /// 任务取消
        /// </summary>
        /// <param name="msg">取消任务的信息</param>
        /// <param name="_cache">缓存服务</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult<ApiResult>> Cancel([FromServices] IMemoryCache _cache, CancelInfo msg)
        {
            try
            {

                if (_jobRepoitory.CheckExist(x => x.Id == msg.Mission))
                {
                    var b = await _jobRepoitory.FindByIdAsync(msg.Mission);
                    if (b.Status == TaskState.Pending || b.Status == TaskState.BeforeGet)
                    {
                        if (b.RobotId != null)
                        {
                            List<Robot> robots = _cache.Get<List<Robot>>("Robots");
                            if (robots != null)
                            {
                                var robot = robots.FirstOrDefault(x => x.Id == b.RobotId);
                                if (robot != null)
                                {
                                    robot.RequestIdle();
                                    robot.CurrentJob = null;
                                    robot.JobId = null;
                                    await _robotRepository.UpdateEntityAsync(robot);
                                }
                            }
                        }
                        return ApiResultHelper.Success("succeed");
                    }
                    else
                    {
                        return ApiResultHelper.Error("任务已经进行无法取消");
                    }
                }
                else
                    return ApiResultHelper.Error("任务不存在");

            }
            catch (Exception ex)
            {
                return ApiResultHelper.Error($"取消出错!服务器发生错误:{ex.Message}");
            }


        }
        #endregion

        #region 更新
        /// <summary>
        /// 更新任务
        /// </summary>
        /// <param name="job">任务信息</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ApiResult> Edit([FromBody] Job job)
        {
            var newjob = await _jobRepoitory.FindByIdAsync(job.Id);
            if (newjob == null) return ApiResultHelper.Error("没有找到该任务");



            bool b = await _jobRepoitory.UpdateEntityAsync(newjob);
            if (!b) return ApiResultHelper.Error("修改失败");

            //_mCache.Update<Job>("Jobs", newjob);
            return ApiResultHelper.Success(newjob);
        }
        #endregion

        #region 删除


        /// <summary>
        /// 通过Id终止任务
        /// </summary>
        /// <param name="id">要终止的任务Id</param>
        /// <param name="_cache">缓存服务</param>
        /// <returns></returns>
        [HttpPost("{id}")]
        public async Task<ActionResult<ApiResult>> Abort([FromServices] IAppCache _cache, string id)
        {
            var job = await _jobRepoitory.FindByIdAsync(id);
            bool result = false;
            if (job.Type != TaskType.Charge)
            {
                result = ReportToMes(job, "Aborted");
            }
            if (result || job.Type == TaskType.Charge)
            {
                job.UpdateTime = DateTime.Now;
                job.Status = TaskState.Abort;
                var b = await _jobRepoitory.UpdateEntityAsync(job);
                if (!b)
                    return ApiResultHelper.Error("取消失败,数据库中无法取消该任务!");
                List<Robot> robots = null;
                _cache.TryGetValue<List<Robot>>("Robots", out robots);
                if (robots != null)
                {
                    var robot = robots.FirstOrDefault(x => x.Id == job.RobotId);
                    if (robot != null)
                    {
                        if (job.Type != TaskType.Charge)
                        {
                            robot.UmStop();
                            robot.CurrentJob = null;
                            robot.JobId = null;
                        }
                        else
                        {
                            if (robot.CurrentJob != null && robot.CurrentJob.Id == job.Id)
                            {
                                robot.CurrentJob = null;
                                robot.JobId = null;
                            }
                        }
                        await _robotRepository.UpdateEntityAsync(robot);
                        robot.UmStop();
                    }

                }

                //_mCache.Delete<Job>("Jobs", new Job() { MissionId = id });
                return ApiResultHelper.Success(b);
            }
            else
            {
                return ApiResultHelper.Error("取消失败，MES回复信息错误!");
            }



        }

        /// <summary>
        /// 批量删除任务
        /// </summary>
        /// <param name="ids">批量删除的任务Id</param>
        /// <returns></returns>
        [HttpDelete]
        public async Task<ActionResult<ApiResult>> DeleteByIds([FromServices] IAppCache _cache, [FromBody] dynamic[] ids)
        {
            var newjobs = await _jobRepoitory.QueryAsync(x => ids.Contains(x.Id));
            List<Robot> robots = null;
            _cache.TryGetValue<List<Robot>>("Robots", out robots);
            foreach (var newjob in newjobs)
            {

                if ((int)newjob.Status < (int)TaskState.Complete || newjob.Status == TaskState.Charging)
                {
                    bool result = false;
                    if (newjob.Type != TaskType.Charge)
                    {
                        result = ReportToMes(newjob, "Aborted");
                    }
                    if (result || newjob.Type == TaskType.Charge)
                    {
                        if (robots != null)
                        {
                            var robot = robots.Find(x => x.Id == newjob.RobotId);
                            if (robot != null)
                            {
                                if (newjob.Type != TaskType.Charge)
                                {
                                    robot.UmStop();
                                    robot.CurrentJob = null;
                                    robot.JobId = null;
                                }
                                else
                                {
                                    if (robot.CurrentJob != null && robot.CurrentJob.Id == newjob.Id)
                                    {
                                        robot.CurrentJob = null;
                                        robot.JobId = null;
                                    }
                                }
                                await _robotRepository.UpdateEntityAsync(robot);
                            }

                        }
                    }
                    else
                    {
                        return ApiResultHelper.Error("删除失败,无法通知mes终止任务");
                    }
                }
                

            }

            bool b = await _jobRepoitory.DeleteByIdsAsync(ids);
            if (!b) return ApiResultHelper.Error("删除失败");


            return ApiResultHelper.Success(b);
        }
        #endregion

        #region 查找 
        /// <summary>
        /// 分页查找任务
        /// </summary>
        /// <param name="page">分页数</param>
        /// <param name="limit">行数</param>
        /// <param name="query">筛选条件</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ApiResult> GetTaskByPage([FromServices] IMapper mapper,  int page, int limit, [FromQuery] string query)
        {
            RefAsync<int> total = 0;
            try
            {
                if (query != null)
                {
                    JObject jobject = JObject.Parse(query);
                    List<IConditionalModel> models = new List<IConditionalModel>();
                    foreach (var key in jobject.Properties())
                    {
                        if (key.Name.ToLower() == "type")
                        {
                            if (key.Value.ToString() != "-1")
                            {
                                models.Add(new ConditionalModel()
                                {
                                    FieldName = key.Name,
                                    FieldValue = key.Value.ToString(),
                                    ConditionalType = ConditionalType.Equal,
                                    FieldValueConvertFunc = it => SqlSugar.UtilMethods.ChangeType2(it, typeof(TaskType))
                                });
                            }

                        }
                        else if (key.Name.ToLower() == "status")
                        {
                            if (key.Value.ToString() != "-1")
                            {
                                models.Add(new ConditionalModel()
                                {
                                    FieldName = key.Name,
                                    FieldValue = key.Value.ToString(),
                                    ConditionalType = ConditionalType.Equal,
                                    FieldValueConvertFunc = it => SqlSugar.UtilMethods.ChangeType2(it, typeof(TaskState))
                                });
                            }

                        }
                        else if (key.Name.ToLower() == "createtime")
                        {
                            models.Add(new ConditionalModel()
                            {
                                FieldName = key.Name,
                                FieldValue = key.Value.ToString(),
                                ConditionalType = ConditionalType.GreaterThanOrEqual,
                                FieldValueConvertFunc = it => SqlSugar.UtilMethods.ChangeType2(it, typeof(DateTime))
                            });
                            models.Add(new ConditionalModel()
                            {
                                FieldName = key.Name,
                                FieldValue = Convert.ToDateTime(key.Value.ToString()).AddDays(1).ToString("yyyy-MM-dd"),
                                ConditionalType = ConditionalType.LessThan,
                                FieldValueConvertFunc = it => SqlSugar.UtilMethods.ChangeType2(it, typeof(DateTime))
                            });
                        }
                        else
                        {
                            models.Add(new ConditionalModel()
                            { FieldName = key.Name, FieldValue = key.Value.ToString(), ConditionalType = ConditionalType.Equal });
                        }




                    }
                    var jobs = await _jobRepoitory.QueryAsync(models, page, limit, total);
                    var jobDtos = mapper.Map<List<JobDto>>(jobs);
                    return ApiResultHelper.Success(jobDtos.OrderByDescending(x => x.CreateTime).ToArray(), total);
                }
                else
                {
                    var jobs = await _jobRepoitory.QueryAsync(page, limit, total);
                    var jobDtos = mapper.Map<List<JobDto>>(jobs);
                    return ApiResultHelper.Success(jobDtos.OrderByDescending(x => x.CreateTime).ToArray(), total);
                }
            }
            catch (Exception ex)
            {
                return ApiResultHelper.Error($"查询出错:{ex.Message}");
            }
        }


        /// <summary>
        /// 查找实时任务
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<ApiResult> GetRealTask([FromServices] IMapper mapper, int page, int limit)
        {
            RefAsync<int> total = 0;
            try
            {
                var data = await _jobRepoitory.QueryAsync(x => x.CreateTime > DateTime.Today.AddDays(-1) &&
                 (int) (x.Status) < (int)TaskState.Complete, page, limit, total);
                var jobDtos = mapper.Map<List<JobDto>>(data);
                return ApiResultHelper.Success(jobDtos.OrderByDescending(x => x.CreateTime).ToArray(), total);
            }
            catch (Exception ex)
            {
                return ApiResultHelper.Error($"查询出错:{ex.Message}");
            }
        }

        /// <summary>
        /// 查找任务类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("{type?}")]
        public async Task<ApiResult> GetJobTypes()
        {
            Dictionary<string, string> types = new Dictionary<string, string>();

            return await Task<ApiResult>.Run<ApiResult>(() =>
            {
                foreach (TaskType value in Enum.GetValues(typeof(TaskType)))
                {
                    FieldInfo fi = value.GetType().GetField(value.ToString());
                    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    types.Add(attributes[0].Description, Enum.GetName<TaskType>(value));
                }
                return ApiResultHelper.Success(types);

            });


        }

        /// <summary>
        /// 查找任务状态
        /// </summary>
        /// <returns></returns>
        [HttpGet("{type?}")]
        public async Task<ApiResult> GetJobStatus()
        {
            Dictionary<string, string> types = new Dictionary<string, string>();

            return await Task<ApiResult>.Run<ApiResult>(() =>
            {
                foreach (TaskState value in Enum.GetValues(typeof(TaskState)))
                {
                    FieldInfo fi = value.GetType().GetField(value.ToString());
                    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    types.Add(attributes[0].Description, Enum.GetName<TaskState>(value));
                }
                return ApiResultHelper.Success(types);

            });


        }


        /// <summary>
        /// 汇报给MES
        /// </summary>
        /// <param name="job"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        private bool ReportToMes(Job job, string status)
        {

           
            string url = _options.CurrentValue.CompleteUrl;
            var data = new
            {
                Command = "Result",
                Id = job.Id,
                Status = status,
                Remark = "网页人工取消"
            };
            string reportinfo = JsonConvert.SerializeObject(data);
            _logger.LogInformation($"Abort job report the mes url {url} data is:{reportinfo}");

            ResponseResult apiResult = new ResponseResult() { Data = "failed" };

          

            RetryTool.Retry(() =>
            {
                string responseData = HttpHelper.RequestPost(_options.CurrentValue.DeliveryUrl, JsonConvert.SerializeObject(data));
                _logger.LogInformation($"Report Abort job receive the mes data is:{responseData}");
                apiResult = JsonConvert.DeserializeObject<ResponseResult>(responseData);
                Thread.Sleep(500);
            }, 5);

            return apiResult?.Data.ToLower() == "succeed";

             

        }




        #endregion

    }


}
